﻿using IP2Region.Net.Abstractions;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using Shyjus.BrowserDetection;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Zhp.Auth.IService;
using Zhp.Auth.Model;
using Zhp.Common.Appsetting;
using Zhp.Common.Helper;
using Zhp.Common.WebApp;

namespace Zhp.Auth.Service
{
    public class JwtTokenService : IJwtTokenService
    {
        IOnlineService _onlineSvc;
        ICurrentUser _currentUser;
        HttpContext _httpContext;
        ISearcher _ipSearcher;
        IBrowserDetector _browser;

        public JwtTokenService(
            IOnlineService onlineSvc, 
            ICurrentUser currentUser, 
            IHttpContextAccessor httpContextAccessor, 
            ISearcher searcher, 
            IBrowserDetector browser)
        {
            _onlineSvc = onlineSvc;
            _currentUser = currentUser;
            _httpContext = httpContextAccessor.HttpContext;
            _ipSearcher = searcher;
            _browser = browser;
        }

        public (string, string) Generate2Token(LoginUserModel user)
        {
            var remoteIp = _httpContext.Connection.RemoteIpAddress?.ToString() ?? "0.0.0.0";
            var onlineUser = new OnlineUserModel
            {
                TokenId = user.TokenId,
                UserId = user.UserId,
                UserName = user.UserName,
                NickName = user.NickName,
                RoleIds = user.RoleIds,
                RequestIp = remoteIp,
                IpAddress = _ipSearcher.Search(remoteIp),
                OperatingSystem = _browser.Browser?.OS,
                DeviceType = _browser.Browser?.DeviceType,
                BrowserName = _browser.Browser?.Name,
                Version = _browser.Browser?.Version,
                LoginTime = user.LoginTime,
                CreateTime = DateTime.Now,
            };

            string accessToken = CreateAccessToken(onlineUser);
            string refreshToken = CreateRefreshToken(onlineUser);

            _onlineSvc.AddOnlineUser(onlineUser);

            return (accessToken, refreshToken);
        }

        public (string, string) RefreshGenerate2Token()
        {
            var online = _onlineSvc.IsOnline(_currentUser.TokenId.ToString(), _currentUser.UserId.ToString());
            if (online.IsOnline)
            {
                online.CurrentUserInfo.CreateTime = DateTime.Now;

                string accessToken = CreateAccessToken(online.CurrentUserInfo);
                string refreshToken = CreateRefreshToken(online.CurrentUserInfo);

                _onlineSvc.RefreshOnlineUser(online.CurrentUserInfo);

                return (accessToken, refreshToken);
            }
            else
            {
                return ("", "");
            }
        }

        private string CreateAccessToken(OnlineUserModel user)
        {
            var claims = new Claim[]
            {
                new Claim(ClaimTypes.Sid, user.UserId.ToString()),
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(ClaimTypes.GivenName, user.NickName),
                new Claim(ClaimTypes.Role, user.RoleIds.ToJson()),
                new Claim(JwtRegisteredClaimNames.Jti, user.TokenId.ToString())//jwt编号
            };

            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SigningKey));
            var jwt = new JwtSecurityToken(
                issuer: jwtOptions.Issuer,
                audience: jwtOptions.Audience,
                claims: claims,
                notBefore: user.CreateTime,
                expires: _onlineSvc.GetAccessExpiresDate(user.CreateTime),
                signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
            );
            return new JwtSecurityTokenHandler().WriteToken(jwt);
        }

        /// <summary>
        /// 生成刷新token
        /// </summary>
        /// <param name="now"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        private string CreateRefreshToken(OnlineUserModel user)
        {
            var claims = new Claim[]
            {
                new Claim(ClaimTypes.Sid, user.UserId.ToString()),
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(ClaimTypes.GivenName, user.NickName),
                new Claim(JwtRegisteredClaimNames.Jti, user.TokenId.ToString())//jwt编号
            };

            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SigningKey));
            var jwt = new JwtSecurityToken(
                issuer: jwtOptions.Issuer,
                audience: jwtOptions.Audience,
                claims: claims,
                notBefore: user.CreateTime,
                expires: _onlineSvc.GetRefreshExpiresDate(user.CreateTime),
                signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
            );
            return new JwtSecurityTokenHandler().WriteToken(jwt);
        }

    }
}
